
package com.x52im.rbchat.logic.profile.voice;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.eva.android.widget.DataLoadableActivity;
import com.eva.android.HttpFileDownloadHelper;
import com.eva.android.VoicePlayer;
import com.eva.android.widget.AProgressDialog;
import com.eva.android.widget.DataLoadingAsyncTask;
import com.eva.android.widget.SimpleGridView;
import com.eva.android.widget.SimpleGridView.DefaultElementDTO;
import com.eva.android.widget.SimpleGridView.DefaultItemAction;
import com.eva.android.widget.SimpleGridView.DefaultListAdapter;
import com.eva.android.widget.WidgetUtils;
import com.eva.android.widget.WidgetUtils.ToastType;
import com.eva.android.widget.alert.AlertDialog;
import com.eva.framework.dto.DataFromServer;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.x52im.rbchat.R;
import com.x52im.rbchat.logic.chat_root.model.Message.DownloadStatus;
import com.x52im.rbchat.logic.chat_root.model.Message.SendStatusSecondaryResult;
import com.x52im.rbchat.logic.chat_root.sendvoice.SendVoiceHelper;
import com.x52im.rbchat.utils.VoicePlayerEx;
import com.x52im.rbchat.logic.profile.photo.PhotosViewActivity;
import com.x52im.rbchat.logic.profile.photo.PhotosViewActivity.IdentDTO;
import com.x52im.rbchat.logic.profile.photo.ViewPhotoActivity;
import com.x52im.rbchat.permission2.PermissionManager;
import com.x52im.rbchat.utils.IntentFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;

/**
 * “我的声音”Activity实现类.
 * 
 * @author Jack Jiang(http://www.52im.net/space-uid-1.html)
 * @since 2.5
 */
public class PVoiceViewActivity extends DataLoadableActivity 
{
	private final static String TAG = PVoiceViewActivity.class.getSimpleName();
	
	// 暂存从Intent中传过来的好友信息数据（将要用于界面展现）:
	// 本参数是必须的，表示查看/管理的是谁的相册
	private String voiceOfUid = null;
	// 本参数是必须的，true表示是否有上传、删除等功能
	// (通常是本地用户查看自已的相册时)，否则表示仅用查看权限（而无法上
	// 传、删除等）通常用于查看别人的相册时
	private boolean canMgr = false;

	/** 布局：没有数据时的提示 */
	private LinearLayout llNoAlarms = null;
	/** 组件：语音列表 */
	private SimpleGridView onlineGridView = null;
	
	/** 发送语音留言对话框 */
	private UploadPVoiceDialog sendVoiceDialog = null;
	
	private AProgressDialog uploadingPd = null;
	
	protected void onPause()
	{
		super.onPause();
		// 如果真在进行语音留言录制的话就hide它
		if(sendVoiceDialog != null)
			sendVoiceDialog.hide();
	}
	@Override
	protected void onDestroy()
	{
		// 释放ListAdapter中需要释放的资源
		if(onlineGridView.getGridViewAdapter() != null)
			((ListAdapterImpl)(onlineGridView.getGridViewAdapter())).forParentDestraoy();
		
		// 如果真在进行语音留言录制的话就销毁它
		if(sendVoiceDialog != null)
			sendVoiceDialog.dismiss();
		//
		super.onDestroy();
	}
	
	@Override
	public void finish()
	{
		//** 回调时把当前的最新声音数返回给上一层界面（如果本次已上传新声音则以便即时显示）
		Bundle bundle = new Bundle(); 
		// 当前相片数
		bundle.putInt("__current_count_", onlineGridView.getGridViewAdapter().getListData().size()); 
		Intent mIntent = new Intent(); 
		mIntent.putExtras(bundle); 
		setResult(RESULT_OK, mIntent); 
		super.finish();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void initDataFromIntent()
	{
		// 解析从intent中传过来的数据：
		ArrayList intentDatas = IntentFactory.parsePVoiceViewActivityIntent(getIntent());
        voiceOfUid = (String)intentDatas.get(0);
		canMgr = (Boolean)intentDatas.get(1);
	}
	
	/**
	 * 本方法由父类的onCreate()调用，子类可在此方法中实现自已的UI显示逻辑。
	 */
	@Override
	protected void initViews(Bundle savedInstanceState)
	{
		//设定自定义标题栏（设定此值即意味着开启自定义标题栏的使用，必须要在setContentView前设定）
		customeTitleBarResId = R.id.main_more_profile_pvoice_gridview_list_titleBar;
		//养成良好习惯：首先设置主layout，确保后绪的操作中使用到的组件都可以被find到
		setContentView(R.layout.main_more_profile_pvoice_gridview_list);

		//列表无数据时的UI提示信息组件
		llNoAlarms = (LinearLayout)findViewById(R.id.main_more_profile_pvoice_gridview_list_noAlarmsLL);
		//** views
		onlineGridView = createGridViewObjForOnline(this, getOnlineGridViewListDatas(this));
		// 为了重用SimpleGridView类，只能独立加载SimpleGridView了，不要忘了，不然ui上就看不见了！！
		((ViewGroup)findViewById(R.id.main_more_profile_pvoice_gridview_list_contentLL))
			.addView(onlineGridView);
		//
		uploadingPd = new AProgressDialog(this, $$(R.string.main_more_profile_pvoice_viewall_uploading));
		
		if(canMgr)
		{
			this.getCustomeTitleBar().getRightGeneralButton().setVisibility(View.VISIBLE);
			this.getCustomeTitleBar().getRightGeneralButton().setBackgroundResource(R.drawable.main_more_profile_voice_add_btn);
			this.setTitle($$(R.string.main_more_profile_pvoice_viewall_forme_title));
		}
		else
		{
			this.getCustomeTitleBar().getRightGeneralButton().setVisibility(View.GONE);
			this.setTitle($$(R.string.main_more_profile_pvoice_viewall_forother_title));
		}

		// ui初始化完成后，强制刷新一下列表显示，以便当列表没有数据时可以即时显示空数据提示ui
		onlineGridView.getGridViewAdapter().notifyDataSetChanged();
	}
	
	/**
	 * 本方法由父类的onCreate()调用，子类可在此方法中为各UI功能组件增加事件临听。
	 */
	@Override
	protected void initListeners()
	{
		// 语音录制和上传按钮
		this.getCustomeTitleBar().getRightGeneralButton().setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View v)
			{
				// 开始动态权限申请（用于targetSDKVersion>=23，即Android6.0及以上系统时）
				PermissionManager.requestPermission_RECORD_AUDIO(PVoiceViewActivity.this
						// 权限获取成功或已经取得此权限时
						, new Observer(){
							@Override
							public void update(Observable o, Object arg) {

								//** 权限正常获取，走正常的代码逻辑。。。。

								// 把句柄缓存起 ，以便 下次打开时能快一点（经实测，跟每次都new SendVoiceDialog，确实要快很多哦！）
								if(sendVoiceDialog == null)
								{
									sendVoiceDialog = new UploadPVoiceDialog(PVoiceViewActivity.this) {
										/**
										 * 真正的上传实现方法.
										 *
										 * @param voiceFileNameAfterPreprocess 经过上传前的预处理（预处理包括文件合法性检查、按MD5码重命名等）后的语音文件文件名
										 * @see UploadPVoiceWrapper#processUploadImpl(String)
										 */
										@Override
										protected void processUploadVoice(String voiceFileNameAfterPreprocess)
										{
											uploadNewVoice(voiceFileNameAfterPreprocess);
										}
									};
								}
								// 显示之
								sendVoiceDialog.show();
							}
						}
						, null);
			}
		});
	}
	
	// 根据传进来的每页元素数据集，生成该页的GridView对象
	private SimpleGridView createGridViewObjForOnline(Activity context, ArrayList<DefaultElementDTO> childListDatas)
	{
		return new SimpleGridView(context 
				, R.layout.main_more_profile_pvoice_gridview, R.id.main_more_profile_pvoice_gridview_id
				, R.layout.main_more_profile_pvoice_gridview_item, R.id.main_more_profile_pvoice_gridview_item_textView, R.id.main_more_profile_pvoice_gridview_item_imageView
				, childListDatas)
		{
			// 重写adapter创建方法，实现自定义的view展现逻辑
			protected DefaultListAdapter createListAdapter(
					Activity context, final int maingridviewitem_layout_res_id
					, final int maingridviewitem_text_view_id, final int maingridviewitem_image_view_id
					, ArrayList<DefaultElementDTO> listDatas)
			{
				DefaultListAdapter adapter = new ListAdapterImpl(context
						, maingridviewitem_layout_res_id
						, maingridviewitem_text_view_id 
						, maingridviewitem_image_view_id); 
				// 
				adapter.setListData(listDatas);
				return adapter;
			}
		};
	}
	
	/**
	 * 实现语音文件的真正上传实现方法.
	 * 
	 * @param voiceFileNameAfterPreprocess
	 */
	private void uploadNewVoice(String voiceFileNameAfterPreprocess)
	{
		// 处理结果观察者实现对象
		SendStatusSecondaryResult sendStatusSecondaryResult = new SendStatusSecondaryResult(){
			@Override
			public void processing()
			{
				uploadingPd.show();
			}

			@Override
			public void processFaild()
			{
				if(uploadingPd.isShowing())
					uploadingPd.dismiss();
				WidgetUtils.showToast(PVoiceViewActivity.this
						, $$(R.string.main_more_profile_pvoice_viewall_uploadfaild), ToastType.WARN);
			}

			@Override
			public void processOk()
			{
				if(uploadingPd.isShowing())
					uploadingPd.dismiss();

				WidgetUtils.showToast(PVoiceViewActivity.this
						, $$(R.string.main_more_profile_pvoice_viewall_uploadok), ToastType.OK);
				// 上传成功完成后刷新界面数据（如果要体验好的话，肯定是本地add一条到列表中，但本地add
				// 时需要服务端生成的resource_id等，而目前封装的这么多层，干脆就不折腾了，就这样吧）
				loadData();
			}
		};
		// 处理个人介绍语音文件的上传和消息的发送
		SendVoiceHelper.processVoiceUpload(this, voiceFileNameAfterPreprocess
				, sendStatusSecondaryResult, true);
	}
	
	//------------------------------------------------------------------------------------------------
	@Override
	protected DataFromServer queryData(String... arg0)
	{
		return  PhotosViewActivity.queryProfileResource(voiceOfUid, 1);
	}
	@Override
	protected void refreshToView(Object arg0)
	{
		if(arg0 != null)
		{
//			Vector<Vector> ret = (Vector<Vector>)arg0;
			Vector<Vector> ret = new Gson().fromJson(
					(String)arg0, new TypeToken<Vector<Vector>>(){}.getType());
			
			//## Bug FIX: 20170322 当删除的是最后一个证明音留言完成时，如果判断“ret.size() > 0”
			//##          才刷新列表显示数据则UI将不能及时更新显示内容为空哦。
//			if(ret.size() > 0)
			{
				// 要返回的所有元素列表
				ArrayList<DefaultElementDTO> listDatas = new ArrayList<DefaultElementDTO>();

				for(Vector row : ret)
				{
					IdentDTO cr = PhotosViewActivity.parseProfileResourceToIdentDTO(row, voiceOfUid, 1);

					// 加入该场景（到列表中）
					listDatas.add(new DefaultElementDTO(createOnlineSenceAction(PVoiceViewActivity.this, cr), "" , null));
				}

				// 更新gridview的列表数据并刷新ui显示
				onlineGridView.getGridViewAdapter().setListData(listDatas);
				onlineGridView.getGridViewAdapter().notifyDataSetChanged();
			}
		}
		else
		{
			Log.w(PVoiceViewActivity.class.getSimpleName(), "result==null!!");
		}
	}
	
	// 返回“在线商城”所有元素的数据集
	private ArrayList<DefaultElementDTO> getOnlineGridViewListDatas(final Activity context)
	{
		// 要返回的所有元素列表
		ArrayList<DefaultElementDTO> listDatas = new ArrayList<DefaultElementDTO>();
		// 说明：初始化的时候就用空列表吧，只当用户滑到在线
		//       列表时才实时从服务端取过来，这样能提升用户体验
		// do nothing at init...
		return listDatas; 
	}
		
	private DefaultItemAction createOnlineSenceAction(final Context context, Object indentId)
	{
		return new DefaultItemAction(indentId)
		{
			@Override
			public void actionPerformed(final Object indentId)
			{
			}
		};
	}
	
	/**
	 * GridView的Adapter实现类.
	 */
	private class ListAdapterImpl extends DefaultListAdapter
	{
		private VoicePlayerImpl voicePlayerWrapper = null;
		/** 当前语音留言播放中的实体对象句柄 */
		private IdentDTO _currentVoicePlayingCME = null;
		
		public ListAdapterImpl(Activity context,
				int maingridviewitem_layout_res_id,
				int maingridviewitem_text_view_id,
				int maingridviewitem_image_view_id)
		{
			super(context, maingridviewitem_layout_res_id, maingridviewitem_text_view_id,
					maingridviewitem_image_view_id);
			
			voicePlayerWrapper = new VoicePlayerImpl();
		}
		
		/**
		 * 父Activity销毁时即时释放相关资源。
		 */
		public void forParentDestraoy()
		{
			// 执行音频的release，释放资源
			voicePlayerWrapper.release();
		}
		
		public IdentDTO getIdentData(int position)
		{
			// 索引合法性检查
			if(position < 0 || position > listData.size() - 1)
				return null;
			
			final DefaultElementDTO rowData = listData.get(position);
			if(rowData != null)
				return (IdentDTO)rowData.get__ident__();
			
			return null;
		}
		
		@Override
		public View getView(final int position, View convertView, ViewGroup parent)
		{
			ViewGroup voiceClickableMainRL = null;
			ViewGroup voiceDeleteRL = null;
			//列表item上的：
			TextView viewText = null;
			//列表item上的：
//			ImageView viewImage = null;
			TextView viewCount = null;
			TextView viewSize = null;
			TextView viewDuaration = null;
			ImageView tvContent_playStatus = null;
			ProgressBar tvGetProgressBar = null;

			//---------------------------------------------------------------------------------------- （1）UI初始化
			//当的item布局实例已经存在（不在存，意味着这个item刚好从不可见区移到可见区时）
			//** 根据android的列表ui实现，为了节比资源占用，假如列表有100行而可见区显示5行，那么任何时候
			//** 这个列表中只会有5个item的UI存在，其它的item都是当被转到可见区时自动把自
			//** 已的数据实时地更新列UI上，以便查看，也就是说item的UI并不是与后台数据一
			//** 一对应的，所以正如API文档里说的，convertView并不能确保它总能按你的想法保持不为null
			boolean needCreateItem = (convertView == null);
			//正在操作的列表行的数据集
			IdentDTO extraData = getIdentData(position);
			if(extraData == null)
				return null;
			
			if (needCreateItem)
				//明细item的UI实例化
				convertView = layoutInflater.inflate(itemResId, null);
			//item里的操作组件实例
			voiceClickableMainRL = (ViewGroup) convertView.findViewById(R.id.main_more_profile_pvoice_gridview_item_voiceClickableMainFL); //
			voiceDeleteRL = (ViewGroup)convertView.findViewById(R.id.main_more_profile_pvoice_gridview_item_deleteView_RL); //
			viewText = (TextView) convertView.findViewById(maingridviewitem_text_view_id);////R.id.chatting_list_view_bottom_waves_list_item_txt);
//			viewImage = (ImageView) convertView.findViewById(maingridviewitem_image_view_id);//R.id.chatting_list_view_bottom_waves_list_item_image);
			viewCount = (TextView) convertView.findViewById(R.id.main_more_profile_pvoice_gridview_item_downloadCountView);
			viewSize = (TextView) convertView.findViewById(R.id.main_more_profile_pvoice_gridview_item_fileSizeHumanView);
			viewDuaration = (TextView) convertView.findViewById(R.id.main_more_profile_pvoice_gridview_item_duationView);
			// 播放状态显示组件：当前只针对语音留言方（包括发送的和收到的）
			tvContent_playStatus = (ImageView) convertView.findViewById(R.id.main_more_profile_pvoice_gridview_item_playStatus_for_voice);
			// 下载状态显示组件：当前只针对收到的语音留言方
			tvGetProgressBar = (ProgressBar) convertView.findViewById(R.id.main_more_profile_pvoice_gridview_item_downloadProgress_for_voice);
			
			//---------------------------------------------------------------------------------------- （2）增加事件处理器
			//各操作组件的事件监听器只需要在convertView被实例化时才需要重建（convertView需要被实例化
			//当然就意味着它上面的所有操作组件都已经重新新建了）
			//** 关于事件处理器的说明：事件处理器的增加其实可以不这么麻烦，直接每getView一次就给组件new一个处理器，
			//** 这样做的好处是简单，但显然存在资源浪费（每刷新一次view就新建监听器）。而现在的实现就跟Android的列表
			//** 实现原理一样，在切换到下一组item前，监听器永远只有一屏item的数量（刷新时只需要即时刷新对应item的数据到
			//** 它的监听器里），这样就节省了资源开销！
			if(needCreateItem)
			{
				// 点击播放语音事件处理
				ContentOnClickListener playLIstener = new ContentOnClickListener();
				voiceClickableMainRL.setOnClickListener(playLIstener);
				voiceClickableMainRL.setTag(playLIstener);
				
				// 点击删除语音的事件处理
				DeleteOnClickListener deleteLIstener = new DeleteOnClickListener();
				voiceDeleteRL.setOnClickListener(deleteLIstener);
				voiceDeleteRL.setTag(deleteLIstener);
			}

			//---------------------------------------------------------------------------------------- （3）
			// ********** 设置文本数据
			// 当有管理功能时才显示删除功能总布局（管理功能只用于自已从个人信
			// 息功能进来查看自已的语音时，当然不能管理别人的了），否则不显示
			if(canMgr)
				voiceDeleteRL.setVisibility(View.VISIBLE);
			else
				voiceDeleteRL.setVisibility(View.GONE);
			viewCount.setText(extraData.getView_count());
			viewSize.setText(extraData.getRes_human_size());
			String voiceFileName = extraData.getRes_file_name();
			if(voiceFileName != null)
			{
				// 从文件名中解析出语音时长（单位：秒）
				int duration = SendVoiceHelper.getDurationFromVoiceFileName(voiceFileName);
				// 显示语音时长
				viewDuaration.setText(String.valueOf(duration)+"''");
			}
			
			// ** 设置语音（包括收到的、发出的消息）播放状态的显示
			setupPlayStatusForVoiceView(extraData, tvContent_playStatus);
			
			// ** 设置语音（当前仅针对收到的消息）下载状态的显示
			setupDownloadStatusForVoiceView(extraData, tvGetProgressBar);
			
			//---------------------------------------------------------------------------------------- （4）无需新建listener，只需刷新关键数据到listener
			//** 确保每次item被刷新时都更新操作组件事件监听器中要记录的该item所对应的 列表的行索引号
			//** 这样就能很好地确保行索引号的正确性了
			ContentOnClickListener playListener = (ContentOnClickListener) voiceClickableMainRL.getTag();
			playListener.setContentData(extraData);
			DeleteOnClickListener deleteListener = (DeleteOnClickListener) voiceDeleteRL.getTag();
			deleteListener.setPosition(position);
			
			return convertView;
		}

		/**
		 * 设置语音播放状态的显示.
		 * 
		 * @param entity
		 * @param viewPlayStatus
		 */
		@SuppressLint("ResourceType")
		protected void setupPlayStatusForVoiceView(IdentDTO entity, ImageView viewPlayStatus)
		{
			// 如果当前单元正是“播放中”状态（this.currentVoicePlayingCME == entity当然就意味着是播放中罗）
			if(voicePlayerWrapper.isEntityVoicePlaying(entity))
			{
				int playAnim_resId = 0;
				playAnim_resId = R.drawable.main_more_profile_pvoice_playing_anim;// 逐帧动画不能用Animation.loadAnimation！！否则报“Unknown animation name: animation-list”

				// 开始“播放中”动画的显示
				if(playAnim_resId != 0)
				{
					viewPlayStatus.setImageResource(playAnim_resId);
					((AnimationDrawable) viewPlayStatus.getDrawable()).start();
				}
			}
			// 否则不是处于“播放中”，则尝试恢复它的ui显示为正常状态即可
			else
			{
				int normal_resId = 0;
				normal_resId = R.drawable.main_more_profile_pvoice_gridview_item_voice_icon;
				//
				viewPlayStatus.setImageResource(normal_resId);
			}
		}

		/**
		 * 设置语音下载状态的显示.
		 * 
		 * @param entity
		 * @param viewProgressBar
		 */
		protected void setupDownloadStatusForVoiceView(IdentDTO entity, ProgressBar viewProgressBar)
		{
			// 收到的语音留言消息
//			if(entity.getMsgType() == MsgType.comeVoice)
			{
				int progressStatus = entity.getDownloadStatus().getStatus();
				switch(progressStatus)
				{
					case DownloadStatus.NONE:
					case DownloadStatus.PROCESS_OK:
					case DownloadStatus.PROCESS_FAILD:
						viewProgressBar.setVisibility(View.GONE);
						break;
					case DownloadStatus.PROCESSING:
						// 设置进度条可见
						viewProgressBar.setVisibility(View.VISIBLE);
						// 刷新进度值显示
						viewProgressBar.setProgress(entity.getDownloadStatus().getProgress());
						break;
				}
			}
		}

		@Override
		public void notifyDataSetChanged()
		{
			super.notifyDataSetChanged();
			if(this.getCount() <= 0)
			{
				llNoAlarms.setVisibility(View.VISIBLE);
				if(onlineGridView != null)
					onlineGridView.setVisibility(View.GONE);
			}
			else
			{
				llNoAlarms.setVisibility(View.GONE);
				if(onlineGridView != null)
					onlineGridView.setVisibility(View.VISIBLE);
			}
		}
		
		//------------------------------------------------------------------------------- inner classes
		/**
		 * 语音播放器封装实现类.
		 * <p>
		 * 本类完全参考自{@link com.x52im.rainbowchat.logic.chat_friend.ChatListAdapter}中的同名类.
		 * 
		 * @author Jack Jiang, 2014-03-30
		 * @since 2.5
		 */
		private class VoicePlayerImpl
		{
			private VoicePlayer voicePlayer = null; 
			
			public VoicePlayerImpl()
			{
				this.voicePlayer = new VoicePlayerEx(context, true);
				// 播放完成时就清除“正在播放”记录
				this.voicePlayer.setOnCompletionObserver(new Observer() {
					@Override
					public void update(Observable observable, Object data)
					{
						clearPlayingStatus(true);
					}
				});
			}
			
			private void release()
			{
				// 执行音频的release，释放资源
				voicePlayer.release();
			}
			
			/**
			 * 当前列表单元（语音留言消息）是否处于“播放中”.
			 * 
			 * @param entity
			 * @return true表示播放中，否则处于普通状态
			 */
			private boolean isEntityVoicePlaying(IdentDTO entity)
			{
				return _currentVoicePlayingCME != null && _currentVoicePlayingCME == entity;
			}
			
			private void clearPlayingStatus(boolean updateUI)
			{
				setPlayingStatus(null, updateUI);
			}
			
			private void setPlayingStatus(IdentDTO entity, boolean updateUI)
			{
				_currentVoicePlayingCME = entity;
				if(updateUI)
					// 通知ui刷新播放状态
					ListAdapterImpl.this.notifyDataSetChanged();
			}
			
			/**
			 * 播放语音留言文件.
			 * 
			 * @param 
			 * @param entity 对应列表单元数据对象句柄（目前用于收到的消息下载时使用）
			 * @return true表示正常进入播放过程，否则表示没有成功（调用者将可以据此来即时恢复”播放中“状态等）
			 */
			private boolean playVoice(final IdentDTO entity)
			{
				boolean sucess = false;
				if(_currentVoicePlayingCME != null)
				{
					// 语音留言消息中的此字段存放的就是语音文件的文件名
					String voiceFileName = entity.getRes_file_name();
					if(voiceFileName != null)
					{
						String voiceFilePath = UploadPVoiceHelper.getSendVoiceSavedDirHasSlash(context)+voiceFileName;
						File voiceFile = new File(voiceFilePath);
						
						// 音频文件已经存在（收到的或发出的消息）那就直接播放
						if(voiceFile.exists())
						{
							try{
								voicePlayer.play(voiceFilePath);
								sucess = true;
							}
							catch (Exception e){
								WidgetUtils.showToast(context, context.getString(R.string.chat_playvoice_play_faild), ToastType.WARN);
							}
						}
						// 文件不存在
						else
						{
							new HttpFileDownloadHelper.DownloadAsyncRoot((Activity)context
									, UploadPVoiceHelper.getVoiceDownloadURL(context, voiceFileName)
									, UploadPVoiceHelper.getSendVoiceSavedDir(context))
							{
								@Override
								protected void onPreExecute() 
								{
									//
									entity.getDownloadStatus().setStatus(DownloadStatus.PROCESSING);
									// 状态的改变同时也通知ui刷新显示哦
									ListAdapterImpl.this.notifyDataSetChanged();
								}
								@Override
								protected void onProgressUpdate(Integer... progress) 
								{
									//
									entity.getDownloadStatus().setProgress(progress[0]); 
									// 状态的改变同时也通知ui刷新显示哦
									ListAdapterImpl.this.notifyDataSetChanged();
								}

								@Override
								protected void onPostExecute_onSucess(String fileSavedPath)
								{
									// 成功下载了语音文件（则播放之）
									try{
										voicePlayer.play(fileSavedPath);

										// 设置“播放中”状态（不同于playVoice中的同类方法，因为本代码在
										// 内部类中，无法由调用者来决定清空播放状态，所以要自已来干哦）
										setPlayingStatus(entity, false); // 异步网络加载完成前，playVoice肯定返回的是false，所以“播放中”状态已被清除，所以此处播放时要设置上去哦
										//
										entity.getDownloadStatus().setStatus(DownloadStatus.PROCESS_OK);
										// 状态的改变同时也通知ui刷新显示哦
										ListAdapterImpl.this.notifyDataSetChanged();
									}
									catch (Exception e){
										WidgetUtils.showToast(context, context.getString(R.string.chat_playvoice_play_faild3), ToastType.WARN);
										// 播放失败则清空播放状态（不同于playVoice中的同类方法，因为本代码在
										// 内部类中，无法由调用者来决定清空播放状态，所以要自已来干哦）
										clearPlayingStatus(true);
									}
								}

								@Override
								protected void onPostExecute_onException(Exception exception)
								{
									WidgetUtils.showToast(context, context.getString(R.string.chat_playvoice_play_faild4), ToastType.WARN);
									entity.getDownloadStatus().setStatus(DownloadStatus.PROCESS_FAILD);
									// 播放失败则清空播放状态（不同于playVoice中的同类方法，因为本代码在
									// 内部类中，无法由调用者来决定清空播放状态，所以要自已来干哦）
									clearPlayingStatus(true);
								}
							}.execute();
						}
					}
					// 要播放的文件名为空？显然是未知原因导致的无效数据
					else
					{
//						// 清空播放状态
//						this.clearPlayingStatus(true);
					}
				}

				return sucess;
			}
			
			/**
			 * 停止语音播放.
			 */
			private void stopVoice()
			{
				// 播放失败则清空播放状态
				this.clearPlayingStatus(true);
				
				try
				{
					voicePlayer.stop();
				}
				catch (Exception e)
				{
					Log.w(TAG, e);
				}
			}
		}
		
		/**
		 * 消息内容点击事件监听器.
		 * <p>
		 * 本类完全参考自{@link com.x52im.rainbowchat.logic.chat_friend.ChatListAdapter}中的同名类.
		 */
		private class ContentOnClickListener implements View.OnClickListener
		{
			private IdentDTO contentData = null;
			
			public ContentOnClickListener()
			{
			}

			public void setContentData(IdentDTO contentData)
			{
				this.contentData = contentData;
			}

			@Override
			public void onClick(View v)
			{
					// 如果正在点击的单元正处于”播放中“则此次点击将停止当前正在进行中的播放
					if(voicePlayerWrapper.isEntityVoicePlaying(contentData))
					{
						voicePlayerWrapper.stopVoice();
						return;
					}
					
					// 点击此单元就意味着此语音留言处于“播放中“状态（因为一次只能播放一个，所以可以作为全局变量存起来，只要ListView的单
					// 元对应的是此currentVoicePlayingCME就意味着它正处于”播放中“状态哦）
					voicePlayerWrapper.setPlayingStatus(contentData, true);
					// 播放声音
					boolean playSucess = voicePlayerWrapper.playVoice(contentData);
					// 如果播放成功进行了
					if(playSucess)
						;
					else
					{
						// 播放失败则清空播放状态
						voicePlayerWrapper.clearPlayingStatus(true);
					}
					
//					// 刷新ui以便即进更新播放状态显示
//					AbstractChattingListAdapter.this.notifyDataSetChanged();
			}
		}
		
		/**
		 * 删除按钮事件监听器.
		 */
		private class DeleteOnClickListener implements View.OnClickListener
		{
			int position = 0;

			public void setPosition(int position)
			{
				this.position = position;
			}

			@Override
			public void onClick(View v)
			{
				// 当前正在操作的单元的数据对象
				final IdentDTO extraData = getIdentData(position);
				
				new AlertDialog.Builder(context)
				.setTitle(R.string.general_prompt)  
				.setMessage($$(R.string.main_more_profile_pvoice_viewall_deletehint))
				.setPositiveButton(R.string.general_yes, new DialogInterface.OnClickListener(){
					@Override
					public void onClick(DialogInterface dialog,int which)
					{
						new DataLoadingAsyncTask<String, Integer, DataFromServer>(context
								, $$(R.string.main_more_profile_pvoice_viewall_deleting))
						{
							@Override
							protected DataFromServer doInBackground(String... params)
							{
								// 提交到服务端删除相关资源
								return ViewPhotoActivity.deleteBinaryRes_pvoice(
										extraData.getResource_id(), extraData.getRes_file_name());
							}
							
							@Override
							protected void onPostExecuteImpl(Object arg0)
							{
								// 数据成功从服务端删除后再从界面上删除之，以便即时刷新ui显示
								removeItem(position);
							}
						}.execute();
					}
				}) 
				.setNegativeButton(context.getString(R.string.general_no), null)
				.show(); 
			}
		}
	}
}
